using System;
using System.Text;
using System.Collections.Generic;
using InfoJetSoft.Service.XPath;

//CID 0164 //2008.12.13 //Begin
namespace InfoJetSoft.Service.XPath.Exprs
{
	/// <summary>
	/// Summary description for EqualityExpr.
	/// </summary>
    public class EqualityExpr : IExpr
	{
		private List<IExpr> _relationalList = null;

		public EqualityExpr()
		{
			//
			// TODO: Add constructor logic here
			//
        }

        public object Evaluate(ExprContext context)
        {
            //CID 0788 //2011.02.28 //Begin
            object leftValue = null;
            for (int i = 0; i < this._relationalList.Count; i++)
            {
                IExpr expr = this._relationalList[i];
                if (expr is OperatorExpr)
                {
                    OperatorExpr oper = (OperatorExpr)expr;
                    i++;
                    IExpr nextExpr = this._relationalList[i];
                    object rightValue = nextExpr.Evaluate(context);
                    if (oper.Operator == Operator.Equal || oper.Operator == Operator.NotEqual)
                    {
                        leftValue = this.EqualOrNotEqual(context, leftValue, rightValue, oper.Operator);
                    }
                    else
                    {
                        throw new Exception("Unsupported operator: " + oper.Operator);
                    }
                }
                else
                {
                    if (leftValue == null)
                    {
                        leftValue = expr.Evaluate(context);
                    }
                    else
                    {
                        throw new Exception("Unsupported expr order");
                    }
                }
            }
            return leftValue;
            //CID 0788 //2011.02.28 //End
        }

        //CID 0866 //2011.04.01 //Begin
        public void Visit(IExprVisitor visitor)
        {
            for (int i = 0; i < this._relationalList.Count; i++)
            {
                IExpr expr = this._relationalList[i];
                expr.Visit(visitor);
            }
        }
        //CID 0866 //2011.04.01 //End

        //CID 0788 //2011.02.28 //Begin
        private bool EqualOrNotEqual(ExprContext context, object value1, object value2, Operator op)
        {
            if (value1 is INodeList || value2 is INodeList)
            {
                INodeList nodeList = null;
                object value = null;
                if (value1 is INodeList)
                {
                    nodeList = (INodeList)value1;
                    value = value2;
                }
                else
                {
                    nodeList = (INodeList)value2;
                    value = value1;
                }
                if (value is bool)
                {
                    bool boolValue = (bool)value;
                    if (op == Operator.Equal)
                    {
                        return (boolValue && nodeList.Count > 0) || ((!boolValue) && nodeList.Count <= 0);
                    }
                    else
                    {
                        return !((boolValue && nodeList.Count > 0) || ((!boolValue) && nodeList.Count <= 0));
                    }
                }
                else if (value is double)
                {
                    double doubleValue = (double)value;
                    if (op == Operator.Equal)
                    {
                        foreach (object node in nodeList)
                        {
                            string nodeValue = context.Calculator.GetNodeValue(node);
                            double nodeDoubleValue = NumberFunctions.number(context, nodeValue);
                            if (nodeDoubleValue == doubleValue)
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                    else
                    {
                        foreach (object node in nodeList)
                        {
                            string nodeValue = context.Calculator.GetNodeValue(node);
                            double nodeDoubleValue = NumberFunctions.number(context, nodeValue);
                            if (nodeDoubleValue != doubleValue)
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                }
                else if (value is string)
                {
                    string strValue = (string)value;
                    if (op == Operator.Equal)
                    {
                        foreach (object node in nodeList)
                        {
                            string nodeValue = context.Calculator.GetNodeValue(node);
                            if (nodeValue.Equals(strValue))
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                    else
                    {
                        foreach (object node in nodeList)
                        {
                            string nodeValue = context.Calculator.GetNodeValue(node);
                            if (!nodeValue.Equals(strValue))
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                }
                else if (value is INodeList)
                {
                    INodeList nodeList2 = (INodeList)value;
                    List<string> strList1 = new List<string>();
                    List<string> strList2 = new List<string>();
                    foreach (object node in nodeList)
                    {
                        string nodeValue = context.Calculator.GetNodeValue(node);
                        strList1.Add(nodeValue);
                    }
                    foreach (object node in nodeList2)
                    {
                        string nodeValue = context.Calculator.GetNodeValue(node);
                        strList2.Add(nodeValue);
                    }
                    if (op == Operator.Equal)
                    {
                        foreach (string str1 in strList1)
                        {
                            foreach (string str2 in strList2)
                            {
                                if (str1.Equals(str2))
                                {
                                    return true;
                                }
                            }
                        }
                        return false;
                    }
                    else
                    {
                        foreach (string str1 in strList1)
                        {
                            foreach (string str2 in strList2)
                            {
                                if (!str1.Equals(str2))
                                {
                                    return true;
                                }
                            }
                        }
                        return false;
                    }
                }
                return false;
            }
            else
            {
                if (value1 is bool)
                {
                    bool bool1 = (bool)value1;
                    bool bool2 = BooleanFunctions.boolean(value2);
                    if (op == Operator.Equal)
                    {
                        return bool1 == bool2;
                    }
                    else
                    {
                        return bool1 != bool2;
                    }
                }
                else if (value2 is bool)
                {
                    bool bool2 = (bool)value2;
                    bool bool1 = BooleanFunctions.boolean(value1);
                    if (op == Operator.Equal)
                    {
                        return bool1 == bool2;
                    }
                    else
                    {
                        return !(bool1 == bool2);
                    }
                }
                else if (value1 is double)
                {
                    double double1 = (double)value1;
                    double double2 = NumberFunctions.number(context, value2);
                    if (op == Operator.Equal)
                    {
                        return double1 == double2;
                    }
                    else
                    {
                        return !(double1 == double2);
                    }
                }
                else if (value2 is double)
                {
                    double double2 = (double)value2;
                    double double1 = NumberFunctions.number(context, value1);
                    if (op == Operator.Equal)
                    {
                        return double1 == double2;
                    }
                    else
                    {
                        return !(double1 == double2);
                    }
                }
                else
                {
                    string str1 = StringFunctions.stringFunc(context, value1);
                    string str2 = StringFunctions.stringFunc(context, value2);
                    if (op == Operator.Equal)
                    {
                        return str1.Equals(str2);
                    }
                    else
                    {
                        return !str1.Equals(str2);
                    }
                }
            }
        }
        //CID 0788 //2011.02.28 //End

        public void Print(StringBuilder buffer)
        {
            foreach (IExpr expr in this._relationalList)
            {
                expr.Print(buffer);
            }
        }

        public static IExpr Parse(ExprParser parser)
		{
			IExpr subExpr = RelationalExpr.Parse( parser );
            if (subExpr != null)
			{
                List<IExpr> list = new List<IExpr>();
                list.Add(subExpr);

                OperatorExpr equalityOperator = OperatorExpr.ParseEqualityOperator(parser);
				while( equalityOperator != null )
				{
					list.Add( equalityOperator );

                    IExpr nextSubExpr = RelationalExpr.Parse(parser);
                    if (nextSubExpr == null)
					{
						throw new Exception( "Cannot parse " + parser.XPath );
					}
                    list.Add(nextSubExpr);
					
					equalityOperator = OperatorExpr.ParseEqualityOperator( parser );
				}

                if (list.Count > 1)
                {
                    EqualityExpr equalityExpr = new EqualityExpr();
                    equalityExpr._relationalList = list;
                    return equalityExpr;
                }
                else
                {
                    return subExpr;
                }
			}
			return null;
		}
	}
}
//CID 0164 //2008.12.13 //End
